package cn.com.qtgl.init.tenant.comp.service;

import cn.com.qtgl.apis.builtin.comp.proxy.BuiltinProxy;
import cn.com.qtgl.apis.builtin.model.vo.department.DepartmentConnection;
import cn.com.qtgl.apis.builtin.model.vo.post.PostConnection;
import cn.com.qtgl.apis.builtin.model.vo.user.User;
import cn.com.qtgl.apis.builtin.model.vo.user.UserConnection;
import cn.com.qtgl.init.tenant.model.entity.*;
import cn.com.qtgl.sso.oidc.comp.service.ProfileService;
import cn.com.qtgl.sso.oidc.comp.service.TokenService;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.melonlib.authentication.model.entity.Tenant;
import cn.melonlib.cores.commons.comp.dao.DaoUtils;
import cn.melonlib.cores.commons.comp.service.impl.WorkerBasicService;
import cn.melonlib.cores.commons.comp.utils.FilterTools;
import cn.melonlib.cores.jpa.model.bean.impl.DefaultQuery;
import cn.melonlib.objects.maps.JsonMap;
import org.intellij.lang.annotations.Language;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class InitTenantService extends WorkerBasicService<LocalTenant> {


    @Resource
    private ProfileService profileService;

    @Resource
    private TokenService tokenService;

    @Resource
    private BuiltinProxy builtin;

    @Value("${system.init.tenant.cache:5000}")
    private Integer initDataCache;

    @Resource
    private FilterTools filterTools;

    @Resource
    private DaoUtils daoUtils;

    public LocalTenant initTenant() throws Exception{
        User user=profileService.getUserByToken(tokenService.getClientToken().getAccessToken());
        Tenant tenant=user.getTenant();
        @Language("HQL") String query="from LocalTenant where apiId=?1 and code=?2";
        List<LocalTenant> tenants=this.dao.
                <List<LocalTenant>,DefaultQuery>search(new DefaultQuery(query,List.of(tenant.getId(), tenant.getCode()))).getResult();
        if(CollectionUtil.isEmpty(tenants)){
            LocalTenant localTenant=new LocalTenant();
            BeanUtil.copyProperties(tenant,localTenant,"id");
            localTenant.setApiId(tenant.getId());
            localTenant.setConfig("{}");
            localTenant.setLocalConfig("{}");
            long offset=0;
            DepartmentConnection departmentConnection=builtin.departments(initDataCache,offset, JsonMap.createMap());
            int total=0;
            long dataCount=0L;
            do{
                if(offset!=0){
                    departmentConnection=builtin.departments(initDataCache,offset, JsonMap.createMap());
                }
                total=departmentConnection.getTotalCount();
                logger.info("读取部门数据："+total+":"+"("+offset+"->"+initDataCache+")");
                long dataCached= departmentConnection.getEdges().stream().map(n -> n.getNode()).map(dep -> {
                    LocalDepartment department = new LocalDepartment();
                    BeanUtil.copyProperties(dep, department, "id");
                    department.setApiId(dep.getId());
                    department.setTenantId(dep.getTenant().getId());
                    department.setTenantCode(dep.getTenant().getCode());
                    department.setTenantName(dep.getTenant().getName());
                    department.setCreatorId(user.getOpenid());
                    department.setCreatorCode(user.getUsername());
                    department.setCreatorName(user.getName());
                    department.setCreateDateTime(System.currentTimeMillis());
                    department.setLastModifiedDateTime(System.currentTimeMillis());
                    return dao.save(department).getResult();
                }).collect(Collectors.toList()).size();
                logger.info("成功读取部门数据："+dataCached);
                dataCount+=dataCached;
                offset+=initDataCache;
            }while (offset<total);
            logger.info("总共读取部门数据："+dataCount);
            offset=0;total=0;dataCount=0L;
            PostConnection postConnection=builtin.posts(initDataCache,offset,JsonMap.createMap());
            do{
                if(offset!=0){
                    postConnection=builtin.posts(initDataCache,offset, JsonMap.createMap());
                }
                total=postConnection.getTotalCount();
                logger.info("读取岗位数据："+total+":"+"("+offset+"->"+initDataCache+")");
                long dataCached= postConnection.getEdges().stream().map(n -> n.getNode()).map(p -> {
                    LocalPost post = new LocalPost();
                    BeanUtil.copyProperties(p, post, "id");
                    post.setApiId(p.getId());
                    post.setTenantId(p.getTenant().getId());
                    post.setTenantCode(p.getTenant().getCode());
                    post.setTenantName(p.getTenant().getName());
                    post.setCreatorId(user.getOpenid());
                    post.setCreatorCode(user.getUsername());
                    post.setCreatorName(user.getName());
                    post.setCreateDateTime(System.currentTimeMillis());
                    post.setLastModifiedDateTime(System.currentTimeMillis());
                    return dao.save(post).getResult();
                }).collect(Collectors.toList()).size();
                logger.info("成功读取岗位数据:"+dataCached);
                dataCount+=dataCached;
                offset+=initDataCache;
            }while (offset<total);
            logger.info("总共读取岗位数据："+dataCount);

            offset=0;total=0;dataCount=0L;
            UserConnection userConnection=builtin.users(initDataCache,offset,JsonMap.createMap());
            do{
                if(offset!=0){
                    userConnection=builtin.users(initDataCache,offset, JsonMap.createMap());
                }
                List<String> postsIds=userConnection.getEdges().stream().flatMap(userEdges -> userEdges.getNode().getPositions().stream())
                        .filter(position -> Objects.nonNull(position.getPost()))
                        .map(position -> position.getPost().getId()).toList();
                List<Serializable> postParams=new ArrayList<>();
                postParams.addAll(postsIds);
                postParams.add(user.getTenant().getId());
                @Language("HQL") String postQuery="from LocalPost where  "+daoUtils.filterToQl(filterTools.createFilters().addIn("apiId",postsIds).getConditionsMap())
                        +" and tenantId = ?"+(postsIds.size()+1);
                System.out.println(postQuery);
                JsonMap<LocalPost> localPostJsonMap=this.dao.<List<LocalPost>,DefaultQuery>search(new DefaultQuery(postQuery,postParams)).getResult()
                        .stream().reduce(JsonMap.createMap(),(m,p)->m.append(p.getApiId(),p),(m,p)->null);

                List<String> departmentIds=userConnection.getEdges().stream().flatMap(userEdges -> userEdges.getNode().getPositions().stream()).filter(position -> Objects.nonNull(position.getDept()))
                        .map(position -> position.getDept().getId())
                        .toList();
                @Language("HQL") String departmentQuery="from LocalDepartment where "+daoUtils.filterToQl(filterTools.createFilters().addIn("apiId",departmentIds).getConditionsMap())
                        +" and tenantId = ?"+(departmentIds.size()+1);;
                List<Serializable> departmentParams=new ArrayList<>();
                departmentParams.addAll(departmentIds);
                departmentParams.add(user.getTenant().getId());
                JsonMap<LocalDepartment> localDepartmentJsonMap=this.dao.<List<LocalDepartment>,DefaultQuery>search(new DefaultQuery(departmentQuery,departmentParams)).getResult()
                        .stream().reduce(JsonMap.createMap(),(m,d)->m.append(d.getApiId(),d),(m,d)->null);

                total=userConnection.getTotalCount();
                logger.info("读取用户数据："+total+":"+"("+offset+"->"+initDataCache+")");
                long dataCached= userConnection.getEdges().stream().map(n -> n.getNode()).map(u -> {
                    LocalUser localUser = new LocalUser();
                    BeanUtil.copyProperties(u, localUser, "id");
                    localUser.setApiId(u.getId());
                    localUser.setTenantId(u.getTenant().getId());
                    localUser.setTenantCode(u.getTenant().getCode());
                    localUser.setTenantName(u.getTenant().getName());
                    localUser.setCreatorId(user.getOpenid());
                    localUser.setCreatorCode(user.getUsername());
                    localUser.setCreatorName(user.getName());
                    localUser.setCreateDateTime(System.currentTimeMillis());
                    localUser.setLastModifiedDateTime(System.currentTimeMillis());
                    LocalUser savelocalUser = dao.save(localUser).getResult();
                    List<LocalPosition> localPositions=u.getPositions().stream().map(position -> {
                        LocalPosition localPosition=new LocalPosition();
                        BeanUtil.copyProperties(position,localPosition,"id");
                        localPosition.setApiId(position.getId());
                        localPosition.setPost(localPostJsonMap.get(BeanUtil.getProperty(position,"post.id")));
                        localPosition.setDept(localDepartmentJsonMap.get(BeanUtil.getProperty(position,"dept.id")));
                        localPosition.setUser(savelocalUser);
                        return dao.save(localPosition).getResult();
                    }).toList();
                    return savelocalUser;
                }).collect(Collectors.toList()).size();
                logger.info("成功读用户位数据:"+dataCached);
                dataCount+=dataCached;
                offset+=initDataCache;
            }while (offset<total);
            logger.info("总共读取用户数据："+dataCount);
            //TODO 初始化父子级路径，方便查询
            initDepartmentPath();
            initPostPath();
            return dao.save(localTenant).getResult();
        }else{
            return tenants.get(0);
        }
    }

    public void initDepartmentPath(){
        @Language("HQL") String query="from LocalDepartment where parent is null or parent = ''";
        List<LocalDepartment> departments=this.dao.<List<LocalDepartment>,DefaultQuery>search(new DefaultQuery(query, Collections.emptyList())).getResult();
        departments.forEach(department->{
            department.setPath("/"+department.getCode());
            department.setIdPath("/"+department.getId());
            LocalDepartment saveDepartment=dao.save(department).getResult();
            initDepartmentPath(saveDepartment);
        });
        @Language("HQL") String otherQuery="from LocalDepartment where path is null";
        List<LocalDepartment> others=this.dao.<List<LocalDepartment>,DefaultQuery>search(new DefaultQuery(otherQuery, Collections.emptyList())).getResult();
        others.forEach(
                department->{
                    department.setPath("/"+department.getCode());
                    department.setIdPath("/"+department.getId());
                    dao.save(department).getResult();
                }
        );

    }
    public void initDepartmentPath(LocalDepartment parent){
        @Language("HQL") String query="from LocalDepartment where parent =?1";
        List<LocalDepartment> departments=this.dao.<List<LocalDepartment>,DefaultQuery>search(new DefaultQuery(query, List.of(parent.getCode()))).getResult();
        departments.forEach(department->{
            department.setPath(parent.getPath()+"/"+department.getCode());
            department.setIdPath(parent.getIdPath()+"/"+department.getId());
            LocalDepartment saveDepartment=dao.save(department).getResult();
            initDepartmentPath(saveDepartment);
        });
    }

    public void initPostPath(){
        @Language("HQL") String query="from LocalPost where parentCode is null or parentCode = ''";
        List<LocalPost> posts=this.dao.<List<LocalPost>,DefaultQuery>search(new DefaultQuery(query, Collections.emptyList())).getResult();
        posts.forEach(post->{
            post.setPath("/"+post.getCode());
            post.setIdPath("/"+post.getId());
            LocalPost savePost=dao.save(post).getResult();
            initPostPath(savePost);
        });
        @Language("HQL") String otherQuery="from LocalPost where path is null";
        List<LocalPost> others=this.dao.<List<LocalPost>,DefaultQuery>search(new DefaultQuery(otherQuery, Collections.emptyList())).getResult();
        others.forEach(
                post->{
                    post.setPath("/"+post.getCode());
                    post.setIdPath("/"+post.getId());
                    dao.save(post).getResult();
                }
        );
    }

    public void initPostPath(LocalPost parent){
        @Language("HQL") String query="from LocalPost where parentCode =?1";
        List<LocalPost> posts=this.dao.<List<LocalPost>,DefaultQuery>search(new DefaultQuery(query, List.of(parent.getCode()))).getResult();
        posts.forEach(post->{
            post.setPath(parent.getPath()+"/"+post.getCode());
            post.setIdPath(parent.getIdPath()+"/"+post.getId());
            LocalPost savePost=dao.save(post).getResult();
            initPostPath(savePost);
        });
    }
}
